
#include "init.h"
#include "Utils.h"
#include <queue>

//================================//
//	---		for User	 ---
//--------------------------------//
std::queue<int> queueX;
std::queue<int> queueY;
bool lockQueue;

int myBoard[100];
int opponentBoard[100];

int my_map_1[][5] = {{2,0,0,0},{3,0,2,0},{3,0,4,0},{4,0,6,0},{5,0,9,0}}; //Isral map
int my_map_2[][5] = {{2,8,0,0},{3,0,1,0},{3,9,7,1},{4,6,2,0},{5,0,3,0}};
int my_map_3[][5] = {{2,7,6,0},{3,4,1,0},{3,2,6,1},{4,5,9,0},{5,3,3,0}};
int my_map_4[][5] = {{2,1,0,0},{3,7,1,1},{3,1,7,0},{4,0,2,1},{5,4,9,0}};
int my_map_5[][5] = {{2,7,4,0},{3,1,4,1},{3,6,9,0},{4,4,2,0},{5,4,5,1}};

int turnPosList[100];
int turnListLen;
int GetRandomNumber(int a, int b, int m)
{
	if(a>=b)
		return -1;
	srand(time(NULL));
	int n = rand();
	srand((n+31215*m+101)%102131);
	n = rand();
	if(n<0)
		n=-n;
	return a+n%(b-a);
}

void AI_Init(Battleship* _this) 
{
	std::cout<<"\nINIT YOUR BOT HERE!!!"<<std::endl;
	Utils::GetInstance()->Initialize();
};

void AI_ChooseFirstPlay(Battleship* _this)
{
	int choose_first_play_arr[3];

	for(int i = 0; i<3;i++)
	{
		choose_first_play_arr[i] = rand()%3;
	}

	_this->SetLottery(choose_first_play_arr);
}
bool foundPatrol = false;
void AI_EndSet(Battleship* _this)
{
	//std::cout<<"*** END SET ***"<<std::endl;
	Utils::GetInstance()->EndSet();
    foundPatrol = false;
}

void AI_SetBoard(Battleship* _this)
{
	int cSet = _this->GetCurrentSet();
	std::cout<<"Set "<<cSet<<" start!"<<std::endl;

	bool result = false;
	
	switch(cSet)
	{
		case 1:
			// set board for Set 1
			result = _this->SetMyBoard(my_map_2);
			break;
		case 2:
			// set board for Set 2
			result = _this->SetMyBoard(my_map_1);
			break;
		case 3:
			// set board for Set 3
			result = _this->SetMyBoard(my_map_3);
			break;
		case 4:
			// set board for Set 4
			result = _this->SetMyBoard(my_map_4);
			break;
		case 5:
			// set board for Set 5
			result = _this->SetMyBoard(my_map_5);
			break;
		default:
			// Out of set
			break;
	}
	if(result)
	{
		std::cout<<"result: SUCCESS"<<std::endl;
	}
	else
	{
		std::cout<<"result: ERROR -- "<<std::endl;
	}

	//--- reset AI attack Pos ---
	for(int i=0; i<100; i++)
	{
		turnPosList[i] = i;
	}
	turnListLen = 100;
	//bong init
	while (!queueX.empty()) queueX.pop();
	while (!queueY.empty()) queueY.pop();
	lockQueue = false;
	//end
};

//bong.nv Lock & Unlock queue
void Lock()
{
	while (lockQueue);
	lockQueue = true;
}

void Unlock()
{
	lockQueue = false;
}
//end

ThreadType* s_thread;
Battleship* battleShip = NULL;
bool check = false;
void ThreadRun()
{
    while (true)
    {
		if (battleShip && check && !queueX.empty())
        {
			Lock();
			int attackPosX = queueX.front();
			int attackPosY = queueY.front();
			Unlock();

            Ship::TypeOfShip type;
	        battleShip->GetOpponentBoard(opponentBoard);
	        // Get the board status at position X,Y 
	        // Note: it will return status of previous turn
	        if(attackPosX >= 0 && attackPosY >= 0)
        	{
        		int k = battleShip->GetBoardStatusAt(opponentBoard, attackPosX, attackPosY);
        		switch(k)
        		{
			        case MISS:
				        std::cout<<"Attack MISS at "<<attackPosX<<";"<<attackPosY<<std::endl;
				        Utils::GetInstance()->ProcessPos(Point(attackPosX,attackPosY),false);
                        check = false;
				        break;
			        case EMPTY:
				        std::cout<<"EMPTY at "<<attackPosX<<";"<<attackPosY<<std::endl;
				        break;
			        case HIT:
				        std::cout<<"Attack HIT at "<<attackPosX<<";"<<attackPosY<<std::endl;
				        Utils::GetInstance()->ProcessPos(Point(attackPosX,attackPosY),true);
                        check = false;
				        break;
                    case DISTROYER:
                        type = Ship::DESTROYER;
					    Utils::GetInstance()->ProcessPos(Point(attackPosX,attackPosY),true);
                        Utils::GetInstance()->FoundShip(Point(attackPosX,attackPosY),type);
                        check = false;
                        break;
                    case PATROL:
                        if (foundPatrol)
                        {
                            type = Ship::PATROL;
                        }
                        else
                        {
                            type = Ship::SUBMARINE;
                            foundPatrol = true;
                        }
					    Utils::GetInstance()->ProcessPos(Point(attackPosX,attackPosY),true);
                        Utils::GetInstance()->FoundShip(Point(attackPosX,attackPosY),type);
                        check = false;
                        break;
                    case BATTLESHIP:
                        type = Ship::BATTLE;
					    Utils::GetInstance()->ProcessPos(Point(attackPosX,attackPosY),true);
                        Utils::GetInstance()->FoundShip(Point(attackPosX,attackPosY),type);
                        check = false;
                        break;
                    case AIRCRAFT_CARRIER:
                        type = Ship::AIRCRAFT;
					    Utils::GetInstance()->ProcessPos(Point(attackPosX,attackPosY),true);
                        Utils::GetInstance()->FoundShip(Point(attackPosX,attackPosY),type);
                        check = false;
                        break;
			        default:
					    std::cout<<"!!!ERROR!!!"<<std::endl;
                        check = false;
				        break;
		        }
        	}
			if (! check)
			{ // we found the result
				Lock();
				queueX.pop();
				queueY.pop();
				Unlock();
			}
        }
        boost::this_thread::sleep(boost::posix_time::milliseconds(50));
    }
    std::cout << "ThreadRun Done" << std::endl;
}

void AI_Update(Battleship* _this)
{
	std::cout << "AI_Update" << std::endl;
	int total = 0;
    while (check && total < 1900)
    {
        boost::this_thread::sleep(boost::posix_time::milliseconds(50));
		total += 50;
        std::cout << "it's checking" << std::endl;
    }
	// Get my current board  status
	//_this->GetMyBoard(myBoard);
	// Get opponent current board  status, it use to calculate the next attack position
	//_this->GetOpponentBoard(opponentBoard);
	
	Point p = Utils::GetInstance()->GuessPos();
	// Sent attack position
	std::cout<<"\nAttack pos: "<<p.first<<";"<<p.second<<std::endl;
	_this->SetAttackPos(p.first, p.second);

	Lock();
	queueX.push(p.first);
	queueY.push(p.second);
	Unlock();

	std::cout << "AI_Update Done" << std::endl;
    battleShip = _this;
    check = true;
}

///////////////////////////////////////////////////////
////					DON'T TOUCH MAIN
///////////////////////////////////////////////////////
int main(int argc, char* argv[]) {
	srand ( time(NULL) );
	AppClientHandlerPtr temp(new AppClientHandler());
	s_con_handler = temp;
	
	//AI process
	Get_BOT_Name(argc,argv);

	Battleship::Init = &AI_Init;
	Battleship::ChooseFirstPlay = &AI_ChooseFirstPlay;
	Battleship::SetBoard = &AI_SetBoard;
	Battleship::Update = &AI_Update;
	Battleship::EndSet = &AI_EndSet;
    s_thread = new ThreadType(ThreadRun);
	p_Battleship = new Battleship(bot_table_x, bot_table_y, bot_name, bot_avatar);

	boost::thread thr_cGame(boost::bind(&Battleship::Run,p_Battleship,s_con_handler));
		//Server process
		Connectiont();
		//End server process
	thr_cGame.join();

	delete p_Battleship;
	//End AI process	
    return 0;
}




